package cn.nju.seg.atg.model;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

import cn.nju.seg.atg.parse.Builder;
import cn.nju.seg.atg.util.CLF;
import cn.nju.seg.atg.util.ConstantValue;

/**
 * 简单CFG节点
 * @author ChengXin
 *
 */
public class SimpleCFGNode {
	/**
	 * 节点名称
	 */
	private String name;
	
	/**
	 * 节点类型
	 */
	private int type;
	
	/**
	 * 当前约束条件的子约束条件分组集合
	 */
	private Constraint constraint;
	
	/**
	 * 节点运行时CLF函数值
	 * 每个复合约束条件的子约束条件都对应一组CLF函数值
	 */
	HashMap<String,Double > values;
	
	/**
	 * 分支节点在路径中的约束谓词是否为真
	 */
	private boolean isTrue;
	
	/**
	 * 无参初始化
	 */
	public SimpleCFGNode()
	{
		this.name = null;
		this.type = 0;
		this.constraint = null;
		this.values = new HashMap<String, Double>();
		this.isTrue = true;
	}
	
	/**
	 * 带参构造函数
	 * @param nodeName
	 * @param nodeType
	 * @param constraint
	 * @param isTrue
	 */
	public SimpleCFGNode(String nodeName, int nodeType, Constraint constraint, boolean isTrue)
	{
		this.name = nodeName;
		this.type = nodeType;
		this.constraint = constraint;
		this.values = new HashMap<String, Double>();
		this.isTrue = isTrue;
	}
	
	/**
	 * 为子约束条件添加运行时CLF函数值
	 * @param constraintExpression
	 * @param c
	 */
	public void addValue(String atomicConstraintExpression, double v)
	{
	    values.put(atomicConstraintExpression, v);
	}
	
	
	/**
	 * 以有序方式将c插入到list中
	 * list中元素以c.x从小到大排序
	 * @param c
	 * @param list
	 */
	private void insertCoodinate2SortedList(Coodinate c, List<Coodinate> list)
	{
		if (list != null)
		{
			int listSize = list.size();
			//判断当前c在list中的位置
			int i=0;
			for (i=0; i<listSize; i++)
			{
				if (c.getX() < list.get(i).getX())
				{
					break;
				}
			}
			//根据c在list中的位置添加c到list
			if (i == listSize)
			{
				list.add(c);
			}
			else if (i>=0 && i<listSize)
			{
				Coodinate tempCoodinate = list.get(listSize-1);
				list.add(tempCoodinate);
				for (int j=(listSize-1); j>i; j--)
				{
					tempCoodinate = list.get(j-1);
					list.set(j, tempCoodinate);
				}
				list.set(i, c);
			}
		}
		else
		{
			list = new ArrayList<Coodinate>();
			list.add(c);
		}
	}
	
	/**
	 * 判断该节点是否为分支节点
	 * @return true|false
	 */
	public boolean isBranchNode()
	{
		if (this.type == ConstantValue.BRANCH_IF || this.type == ConstantValue.BRANCH_FOR)
		{
			return true;
		}
		else
		{
			return false;
		}
	}
	
	/**
	 * 获取可用取值区间
	 * @return 取值区间
	 */
/*	public List<Interval> getEffectiveIntervalList()
	{
		List<Interval> effectiveIntervalList = new ArrayList<Interval>();
		List<List<String>> atomicConstraintGroups = this.constraint.getAtomicConstraintGroups();
		List<Coodinate> tempCoodinateList;
		List<Interval> tempIntervalList;
		if (this.isTrue)
		{
			// 当前约束条件不包含||
			if (atomicConstraintGroups.size() == 1)
			{
				//初始化effectiveIntervalList为全集
				Interval initialInterval = Builder.maxInterval();
				effectiveIntervalList.add(initialInterval);
				int groupSize = atomicConstraintGroups.get(0).size();
				for (int i=0; i<groupSize; i++)
				{
					tempCoodinateList = this.values.get(atomicConstraintGroups.get(0).get(i));
					if (tempCoodinateList != null && tempCoodinateList.size() > 1){
						tempIntervalList = this.getEffectiveIntervalList(tempCoodinateList, this.getComparisonOperator(atomicConstraintGroups.get(0).get(i)));
					}
					else
					{
						Interval tempInterval = new Interval();
						tempIntervalList = new ArrayList<Interval>();
						tempIntervalList.add(tempInterval);
					}
					//求所有原子约束可用区间的交集
					List<Interval> temp = this.getIntersection(effectiveIntervalList, tempIntervalList);
					effectiveIntervalList = temp;
				}
			}
			else	//当前约束条件包含||
			{
				int groupsSize = atomicConstraintGroups.size();
				for (int i=0; i<groupsSize; i++)
				{
					int groupSize = atomicConstraintGroups.get(i).size();
					List<Interval> groupIntervalList = new ArrayList<Interval>();
					//初始化groupIntervalList为全集
					Interval initialInterval = Builder.maxInterval();
					groupIntervalList.add(initialInterval);
					for (int j=0; j<groupSize; j++)
					{
						tempCoodinateList = this.values.get(atomicConstraintGroups.get(i).get(j));
						if (tempCoodinateList != null && tempCoodinateList.size() > 1)
						{
							tempIntervalList = this.getEffectiveIntervalList(tempCoodinateList, this.getComparisonOperator(atomicConstraintGroups.get(i).get(j)));
						}
						else
						{
							Interval tempInterval = new Interval();
							tempIntervalList = new ArrayList<Interval>();
							tempIntervalList.add(tempInterval);
						}
						//求所有原子约束可用区间的交集
						List<Interval> temp = this.getIntersection(groupIntervalList, tempIntervalList);
						groupIntervalList = temp;
					}
					//求所有原子约束分组的区间并集
					List<Interval> temp = this.getUnion(effectiveIntervalList, groupIntervalList);
					effectiveIntervalList = temp;
				}
			}
		}
		else
		{
			//当前约束条件不包含||
			if (atomicConstraintGroups.size() == 1)
			{
				int groupSize = atomicConstraintGroups.get(0).size();
				for (int i=0; i<groupSize; i++)
				{
					tempCoodinateList = this.values.get(atomicConstraintGroups.get(0).get(i));
					if (tempCoodinateList != null && tempCoodinateList.size() > 1)
					{
						//tempCoodinateList的size必须为2个或2个以上，因为一个坐标无法做线性拟合
						tempIntervalList = this.getEffectiveIntervalList(tempCoodinateList, this.getComparisonOperator(atomicConstraintGroups.get(0).get(i)));
					}
					else
					{
						tempIntervalList = new ArrayList<Interval>();
					}
					//求所有原子约束的补集的并集
					List<Interval> temp = this.getUnion(effectiveIntervalList, this.getComplementary(tempIntervalList));
					effectiveIntervalList = temp;
				}
			}
			else	//当前约束条件包含||
			{
				//初始化effectiveIntervalList为全集
				Interval initialInterval = Builder.maxInterval();
				effectiveIntervalList.add(initialInterval);
				int groupsSize = atomicConstraintGroups.size();
				for (int i=0; i<groupsSize; i++)
				{
					int groupSize = atomicConstraintGroups.get(i).size();
					//初始化groupIntervalList为空集
					List<Interval> groupIntervalList = new ArrayList<Interval>();
					for (int j=0; j<groupSize; j++)
					{
						tempCoodinateList = this.values.get(atomicConstraintGroups.get(i).get(j));
						if (tempCoodinateList != null && tempCoodinateList.size() > 1)
						{
							tempIntervalList = this.getEffectiveIntervalList(tempCoodinateList, this.getComparisonOperator(atomicConstraintGroups.get(i).get(j)));
						}
						else
						{
							tempIntervalList = new ArrayList<Interval>();
						}
						List<Interval> temp = this.getUnion(groupIntervalList, this.getComplementary(tempIntervalList));
						groupIntervalList = temp;
					}
					List<Interval> temp = this.getIntersection(effectiveIntervalList, groupIntervalList);
					effectiveIntervalList = temp;
				}
			}
		}
		
		return effectiveIntervalList;
	}
	*/
	/**
	 * 根据一组坐标求解可用取值区间
	 * 通过一组坐标做一元线性拟合，根据比较操作符确定可用取值区间
	 * @param cList
	 * @param comparisonOperator
	 * @return
	 */
/*
	private List<Interval> getEffectiveIntervalList(List<Coodinate> cList, int comparisonOperator)
	{
		List<Interval> effectiveIntervalList = new ArrayList<Interval>();
		CLF tempCLF;
		
		int cListSize = cList.size();
		for (int i=0; i<(cListSize-1); i++)
		{
			tempCLF = new CLF(cList.get(i), cList.get(i+1), comparisonOperator);
			if (tempCLF.getEffectiveInterval() != null)
			{
				effectiveIntervalList.add(tempCLF.getEffectiveInterval());
			}
		}
		
		return effectiveIntervalList;
	}
	
	/**
	 * 获取原子表达式的比较运算符
	 * @param atomicConstraintString
	 * @return 比较运算符
	 */
/*	
	private int getComparisonOperator(String atomicConstraintString)
	{
		if (atomicConstraintString.contains(">="))
		{
			return ConstantValue.SYMBOL_GREATER_EQUAL;
		}
		else if (atomicConstraintString.contains(">"))
		{
			return ConstantValue.SYMBOL_GREATER;
		}
		else if (atomicConstraintString.contains("<="))
		{
			return ConstantValue.SYMBOL_LESS_EQUAL;
		}
		else if (atomicConstraintString.contains("<"))
		{
			return ConstantValue.SYMBOL_LESS;
		}
		else if (atomicConstraintString.contains("=="))
		{
			return ConstantValue.SYMBOL_EQUAL;
		}
		else if (atomicConstraintString.contains("!="))
		{
			return ConstantValue.SYMBOL_UNEQUAL;
		}
		else
		{
			return 0;
		}
	}
	
	/**
	 * 求两个区间的交集
	 * @param list1
	 * @param list2
	 * @return 交集
	 */
/*	public List<Interval> getIntersection(List<Interval> list1, List<Interval> list2)
	{
		List<Interval> intersectionList = new ArrayList<Interval>();
		
		if (list1 != null && list2 != null && !list1.isEmpty() && !list2.isEmpty())
		{
			int listSize1 = list1.size();
			int listSize2 = list2.size();
			int index1 = 0;
			int index2 = 0;
			double tempLeft1;
			double tempLeft2;
			double tempRight1;
			double tempRight2;
			Interval tempInterval = new Interval();
			while(index1 < listSize1 && index2 < listSize2)
			{
				tempLeft1 = list1.get(index1).getLeftBoundary();
				tempLeft2 = list2.get(index2).getLeftBoundary();
				tempRight1 = list1.get(index1).getRightBoundary();
				tempRight2 = list2.get(index2).getRightBoundary();
				
				if (tempLeft1 > tempLeft2)
				{
					if (tempRight1 < tempRight2)
					{
						tempInterval = new Interval();
						tempInterval.setLeftBoundary(tempLeft1);
						tempInterval.setRightBoundary(tempRight1);
						intersectionList.add(tempInterval);
						index1++;
					}
					else if (tempRight1 > tempRight2)
					{
						if (tempLeft1 < tempRight2)
						{
							tempInterval = new Interval();
							tempInterval.setLeftBoundary(tempLeft1);
							tempInterval.setRightBoundary(tempRight2);
							intersectionList.add(tempInterval);
						}
						index2++;
					}
					else
					{
						tempInterval = new Interval();
						tempInterval.setLeftBoundary(tempLeft1);
						tempInterval.setRightBoundary(tempRight1);
						intersectionList.add(tempInterval);
						index1++;
						index2++;
					}
				}
				else if (tempLeft1 < tempLeft2)
				{
					if (tempRight1 > tempRight2)
					{
						tempInterval = new Interval();
						tempInterval.setLeftBoundary(tempLeft2);
						tempInterval.setRightBoundary(tempRight2);
						intersectionList.add(tempInterval);
						index2++;
					}
					else if (tempRight1 < tempRight2)
					{
						if (tempRight1 > tempLeft2)
						{
							tempInterval = new Interval();
							tempInterval.setLeftBoundary(tempLeft2);
							tempInterval.setRightBoundary(tempRight1);
							intersectionList.add(tempInterval);
						}
						index1++;
					}
					else
					{
						tempInterval = new Interval();
						tempInterval.setLeftBoundary(tempLeft2);
						tempInterval.setRightBoundary(tempRight2);
						intersectionList.add(tempInterval);
						index1++;
						index2++;
					}
				}
				else
				{
					if (tempRight1 > tempRight2)
					{
						tempInterval = new Interval();
						tempInterval.setLeftBoundary(tempLeft1);
						tempInterval.setRightBoundary(tempRight2);
						intersectionList.add(tempInterval);
						index2++;
					}
					else if (tempRight1 < tempRight2)
					{
						tempInterval = new Interval();
						tempInterval.setLeftBoundary(tempLeft1);
						tempInterval.setRightBoundary(tempRight1);
						intersectionList.add(tempInterval);
						index1++;
					}
					else
					{
						tempInterval = new Interval();
						tempInterval.setLeftBoundary(tempLeft1);
						tempInterval.setRightBoundary(tempRight1);
						intersectionList.add(tempInterval);
						index1++;
						index2++;
					}
				}
			}
		}
		else
		{
			intersectionList = null;
		}
		
		return intersectionList;
	}
*/	
	/**
	 * 求两个区间的并集
	 * @param list1
	 * @param list2
	 * @return 并集
	 */
/*	private List<Interval> getUnion(List<Interval> list1, List<Interval> list2)
	{
		List<Interval> unionList = new ArrayList<Interval>();
		
		if (list1 == null || list1.size() == 0)
		{
			unionList = list2;
		}
		else if (list2 == null || list2.size() == 0)
		{
			unionList = list1;
		}
		else
		{
			unionList = this.getComplementary(this.getIntersection(this.getComplementary(list1), this.getComplementary(list2)));
		}
		
		return unionList;
	}
	
	/**
	 * 求区间的补集
	 * @param list
	 * @return 补集
	 */
/*	private List<Interval> getComplementary(List<Interval> list)
	{
		List<Interval> complementaryList = new ArrayList<Interval>();

		Interval totalInterval = Builder.maxInterval();
		if (list != null && list.size() != 0)
		{
			int listSize = list.size();
			if (totalInterval.getLeftBoundary() < list.get(0).getLeftBoundary())
			{
				Interval temp = new Interval(totalInterval.getLeftBoundary(), list.get(0).getLeftBoundary());
				complementaryList.add(temp);
			}
			for (int i=0; i<(listSize-1); i++)
			{
				if (list.get(i).getRightBoundary() < list.get(i+1).getLeftBoundary())
				{
					Interval temp = new Interval(list.get(i).getRightBoundary(), list.get(i+1).getLeftBoundary());
					complementaryList.add(temp);
				}
			}
			if (totalInterval.getRightBoundary() > list.get(listSize-1).getRightBoundary())
			{
				Interval temp = new Interval(list.get(listSize-1).getRightBoundary(), totalInterval.getRightBoundary());
				complementaryList.add(temp);
			}
		}
		else
		{
			complementaryList.add(totalInterval);
		}
		
		return complementaryList;
	}
*/
	
	public boolean isEqual(SimpleCFGNode myNode)
	{
		if (this.getName().equals(myNode.getName()))
		{
			return true;
		}
		else
		{
			return false;
		}
	}
		
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public int getType() {
		return type;
	}
	public void setType(int type) {
		this.type = type;
	}

	public Constraint getConstraint() {
		return constraint;
	}

	public void setConstraint(Constraint constraint) {
		this.constraint = constraint;
	}

	public HashMap<String, Double> getValues() {
		return values;
	}
	public void setValues(HashMap<String, Double> values) {
		this.values = values;
	}

	public boolean isTrue() {
		return isTrue;
	}

	public void setTrue(boolean isTrue) {
		this.isTrue = isTrue;
	}
}
